package com.study.tx.mixture.service;

import com.alibaba.fastjson2.JSON;
import com.study.tx.common.utils.ApplicationContextUtils;
import com.study.tx.common.dao.OrderDao;
import com.study.tx.common.entity.MyOrderTransactionEvent;
import com.study.tx.common.entity.Order;
import com.study.tx.common.service.OrderItemService;
import com.study.tx.common.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 订单接口的实现
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2021年02月02日
 */
@Slf4j
@Service("mixtureOrderService")
public class MixtureOrderServiceImpl implements OrderService {
    @Resource
    private OrderDao mixtureOrderDao;
    @Resource
    private OrderItemService mixtureOrderItemService;

    @Override
    public String truncateOrder() {
        int truncateOrder = mixtureOrderDao.truncateOrder();
        log.info("清空 t_order 表结果：{}", truncateOrder);
        int truncateOrderItem = mixtureOrderItemService.truncateOrderItem();
        return "truncateOrder=" + truncateOrder + "，truncateOrderItem=" + truncateOrderItem;
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    @Override
    public String insert(Long userId, Long productId) {
        LocalDateTime now = LocalDateTime.now();
        Order order = new Order();
        order.setUserId(userId);
        order.setOrderStatus(1);
        order.setPayType(1);
        order.setPayMoney(BigDecimal.TEN);
        order.setGmtCreate(now);
        order.setGmtUpdate(now);
        int result4Order = mixtureOrderDao.insert(order);
        System.out.println("操作 t_order 结果：" + result4Order);
        /*if (true) {
            throw new RuntimeException("操作 t_order 之后、 t_order_item 之前抛出了异常！");
        }*/

        int result4OrderItem = 0;
        result4OrderItem = mixtureOrderItemService.insert(order, productId);
        /*try {
            result4OrderItem = mixtureOrderItemService.insert(order, productId);
        } catch (Exception e) {
            System.err.println("捕获到了异常！" + e);
        }*/
        /*try {
            result4OrderItem = mixtureOrderItemService.insert(order, productId);
        } catch (Exception e) {
            throw new RuntimeException("捕获到了异常后再次抛出异常！");
        }*/

        /*if (true) {
            throw new RuntimeException("操作 t_order 之后、 t_order_item 之后抛出了异常！");
        }*/
        // 发送消息到 MQ
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void beforeCommit(boolean readOnly) {
                log.info("调用了 beforeCommit() 方法，readOnly={}，参数：{}", readOnly, JSON.toJSONString(order));
            }

            @Override
            public void afterCommit() {
                // 当数据成功保存到数据库中并且事务提交了，就发送消息到 MQ 中
                log.info("调用了 afterCommit() 方法，参数：{}", JSON.toJSONString(order));
            }

            @Override
            public void beforeCompletion() {
                log.info("调用了 beforeCompletion() 方法，参数：{}", JSON.toJSONString(order));
            }

            @Override
            public void afterCompletion(int status) {
                log.info("调用了 afterCompletion() 方法，status={}，参数：{}", status, JSON.toJSONString(order));
            }
        });
        // 发布一个自定义的事件
        ApplicationContextUtils.applicationContext.publishEvent(new MyOrderTransactionEvent("操作 t_order 的事务事件，请事务提交后执行我~~~", order));
        if (userId == null) {
            // 如果代码未发生异常，由于业务不满足某条件而需要回滚时，有两种解决方法：抛出自定义异常(常用)、通过编程代码回滚(不常用)
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return "result4Order=" + result4Order + "，result4OrderItem=" + result4OrderItem;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer update(Order order) {
        return mixtureOrderDao.update(order);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer delete(Long orderId) {
        return mixtureOrderDao.delete(orderId);
    }

    @Transactional(readOnly = true)
    @Override
    public List<Order> findByUserId(Long userId) {
        return mixtureOrderDao.findByUserId(userId);
    }
}
